package com.test.learnkotlin.test

import android.util.Log.d
import java.util.concurrent.ThreadLocalRandom
import java.util.jar.Attributes.Name
import kotlin.random.Random

/*
    https://blog.csdn.net/qq_35101450/article/details/120232912

    在 Kotlin 中生成随机数
    https://www.techiedelight.com/zh/generate-random-numbers-between-specified-range-kotlin/

 */
fun main() {

//    val userInfo  = UserInfo()
//    userInfo.printAccount()
//        val temp = 0.105
//    val temp = 0.100
//    var rate: Double? = temp
//    println("rate = $rate")
    //rate = 0.105
    //rate = 0.1

    foo1()
//    foo2()

    val randomNum = (1 .. 6).random()
    val randomNum2 = ThreadLocalRandom.current().nextInt(1, 7)
    val randomNum3 = Random.nextInt(1,7)
    println("------------------------------------------")
    println("randomNum = $randomNum , randomNum2 = $randomNum2, randomNum3 = $randomNum3")
    //randomNum = 1 , randomNum2 = 1, randomNum3 = 4


    //匿名函数通常用法是作为参数传递给其他函数或者被其他函数返回

    //开发者就可以轻松实现对kotlin标准库内置函数的定制 ，请看下面示例
    val a1 = "luff".count()
    val a2 = "luff".length
    val a1_y = "luffy love honey".count({letter -> letter == 'y'})

    val c = "luffy love honey".count{
        it == 'y'
    }

    println("a1 = $a1 , a2 = $a2, a1_y = $a1_y c = $c")
    //a1 = 4 , a2 = 4, a1_y = 2 c = 2

    //先定义匿名函数变量，noNameval是变量名，() -> String 表示该变量是无参数且返回值类型为String的匿名函数类型
    val noNameval:() -> String

    noNameval = {
        val holiday = "Mid-Autumn Festival"
        "Happy $holiday"
    }

    //直接赋值
    val noNameval2: () -> String = {
        val holiday = "Mid-Autumn Festival"
        "Happy $holiday"
    }

    //带参数的匿名函数
    val noNameval3:(String) -> String

    //类型推断
    val noNameval4 = {
        val holiday = "Mid-Autumn Festival"
        "Happy $holiday"
    }

    //类型推断也支持带参数的匿名函数，但为了帮助编译器更准确地推断变量类型，必须标明匿名函数的参数名和参数类型。
    val noNameVal5 = { name: String, year: Int ->
        val holiday = "Mid-Autumn Festival"
        "$name,$holiday $holiday,$year"
    }


    //定义参数是函数的函数
    val discountWords = { goodsName:String, hours:Int ->
        val currentYear = 2023
        //给变量加上大括号{}之后，字符串就没有空格了
        "${currentYear}年，${goodsName}双11大促销倒计时还有：$hours 小时"
    }

    showOnBoard("f1",discountWords)

    //函数引用
    //要把函数作为参数传递给其他函数使用，除了使用 lambda，kotlin还提供了函数引用的方式，函数引用可以把一个具名函数转换成一个值参，使用lambda的地方都可以使用函数引用。
    showOnBoard("f1_1",::getDiscountWords)
}

private fun getDiscountWords(goodsName: String, hours: Int): String {
    val currentYear = 2020
    return "${currentYear}年双十一${goodsName}大促销倒计时：$hours 小时"
}

//具名函数
//private fun showOnBoard(goodsName: String, discountWords:(String, Int) ->String){
private inline fun showOnBoard(goodsName: String, discountWords:(String, Int) ->String){
    //返回一个1到24的随机数
    val hour = (1 .. 24).shuffled().last()
    println(discountWords(goodsName,hour))
}

fun foo1() {
    val number1 = listOf(2, 3, 4, 5, 6, 7, 8)
    number1.forEach {
        if (it > 4) {
            return@forEach
        }
        println(it)
    }
    println(" done with anonymous function")
}

fun foo2() {
//    val number2 = listOf(11,14,16,14,5,9,16)
    val number1 = listOf(2, 3, 4, 5, 6, 7, 8)


    run loop@{
        number1.forEach {
            if (it > 4) {
                return@loop
            }
            println(it)

        }
    }

    print(" done with nested loop")
}

class UserInfo {
    lateinit var account: String

    var name: String? = null

    fun printAccount() {

//        println("account = ${account}")
        //上面打印 account 时，抛出异常如下：
        //Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property account has not been initialized

        //检查account 是否已经初始化了
        if (::account.isInitialized) {
            println("account = ${account}")
        } else {
            println("account has not been initialized")
        }

    }
}